Windows PowerShell
PowerShell is built on .NET:
- Windows PowerShell 5.1 is built on top of the .NET Framework v4.5.
- PowerShell is an open source project built on .NET Core.
安装
Windows
以下为安装PowerShell 7.x的方法(Windows内置PowerShell 5.1,PowerShell 7.x可与之并存)。
-
msi
安装,下载安装包点击执行或运行以下命令:msiexec.exe /package PowerShell-7.2.4-win-x64.msi /quiet \ USE_MU=1 ENABLE_MU=1 # 通过Windows Update自动更新PowerShell
-
winget
安装:winget install Microsoft.PowerShell
-
安装为
.NET
全局工具:dotnet tool install|update --global PowerShell # [Admin] 安装PowerShell 7.x
-
通过应用商店安装(有运行权限限制)。
Linux
-
从软件源安装
sudo apt install -y wget apt-transport-https software-properties-common wget -q "https://packages.microsoft.com/config/ubuntu/$(lsb_release -rs)/packages-microsoft-prod.deb" sudo dpkg -i packages-microsoft-prod.deb # Register the repository GPG keys sudo apt update && sudo apt install -y powershell
-
直接从发布页面下载软件包安装。
安装相关路径:
$PSHOME=/opt/microsoft/powershell/7/
;- 用户配置文件:
~/.config/powershell/profile.ps1
; - 用户模块目录:
~/.local/share/powershell/Modules
;
PowerShell命令
PowerShell命令命名规则为Verb-Noun
(动词-名词)形式。
探索PowerShell命令
-
Get-Verb
:获取命令库中多数命令的开头动词(有助于用户使用命令); -
Get-Command
:返回所有已安装的命令。也可以添加参数以过滤列举内容(参数支持通配符*
):Get-Command -Name|Verb|Noun <cmdlet> \ # 按名称/动词/名词匹配 -CommandType Cmdlet, Function, Alias # 按命令类型匹配 -Module <module> # 按模块匹配 -ParameterType Process # 根据命令接受的主要参数的类型筛选 Get-Command Get-Process -Syntax # 获取命令语法
-
Get-Alias
:获取命令别名的信息。Get-Alias -Definition Get-Command,Get-Member # 获取别名 Get-Alias ls,dir # 获取全名
在脚本中尽量使用全名而非别名,以增强可读性。
-
Get-Member
:对输出对象进行操作,并返回对象的属性和方法(可根据参数过滤)。$s = Get-Service -Name w32time $s | Get-Member # 返回对象的类型,及其包含属性的方法的名称、类型和定义
-
Get-Help <cmdlet-name>
:获取命令的文档信息。
模块管理
包管理模块
PowerShellGet
用于查找、安装、更新和发布模块、脚本等内容。
错误:A parameter cannot be found that matches parameter name
AllowPrerelease
.:检查是否安装/导入PowershellGet
模块。
安装/更新PowerShellGet
的两种方法:
-
安装
Nuget
将自动安装PowerShellGet
;Install-PackageProvider -Name NuGet -Force # with Admin
-
直接安装
PowerShellGet
;Install-Module -Name PowerShellGet -AllowClobber -Force
安装模块
Install-Module [-Name] <ModuleName*>
-Scope CurrentUser|AllUsers # AllUsers needs Admin previllege
-AllowPrerelease
-WhatIf
-MinimumVersion 2.0.1 # -RequiredVersion -MaximumVersion
-Force # 安装同名不同版本模块
-AllowClobber # 覆盖同名模块
Update-Module # 参数与Instal-Module相似
Uninstall-Module [-Name] <ModuleName>
安装模块前可以先进行搜索。首先查找本地是否已安装相应模块:
Get-Module -ListAvailable [-Name <ModuleName>] # 从当前当前会话查找模块
-ListAvailable
:列出指定模块的所有本地安装版本(可能包含系统内置版本和用户安装版本)。
如果本地不存在指定模块,可查找Nuget仓库(可使用Nexus搭建镜像仓库)。
Find-Module -Name <ModuleName> # -> PSRepositoryItemInfo
如果本地存在指定模块,找到的模块会被加载到当前会话。
Find-Command -Name <CmdName> -ModuleName <ModName> # -> PSGetCommandInfo
-AllowPrerelease
-RequiredVersion # -MinimumVersion -MaximumVersion
Find-Module
,Find-Command
的返回的结果可以传递给Install-Module
执行安装。
导入模块
位于$env:PSModulePath
路径下加模块会自动被加载。其他模块,在命令行或脚本中执行导入:
Import-Module [-Name] <ModuleName>
$m = Get-Module -ListAvailable PowershellGet, Dism
Import-Module -ModuleInfo $m
Import-Module -Name c:\ps-test\modules\test -Verbose
离线手工安装模块
可以从PowerShell Gallery下载模块的nupkg
包。.nupkg
以zip
格式封装了模块数据以及NuGet相关的描述数据(非模块本身的数据)。NuGet相关数据包括:
_rels/
:包含模块的依赖声明(.rels
文件);package/
:NuGet相关数据;[Content_Types].xml
:描述扩展模块如何与NuGet共同使用;<name>.nuspec
:包的元数据。
手工安装:将.nupkg
中非NuGet相关数据解压到$env:PSModulePath
中的一个路径下,并仅以包名命名该模块的文件夹1。
文档
PowerShell文档介绍了PowerShell的cmdlet、函数、脚本及模块,并解释了PowerShell 语言的元素等概念。在命令行中使用Get-Help cmdlet
来显示帮助主题。
Get-Help cmdname -examples|detailed|full|online
help cmdname # => Get-Help cmdname | more
help Get-Command -Full | Out-GridView # 在独立的文档查看器中查看帮助文档
如果本地没有帮助文件,
Get-Help
会显示自动生成的有关 cmdlet、函数及脚本的帮助。
help
不是Get-Help
的别名:每次仅显示一页内容,需要手动翻页。
Get-Help
会搜索与cmdname
匹配的相关命令(类似于Get-Command
),cmdname
可包含通配符(==如果前后未添加*
,则在名称中间添加*
是无效的通配符==)。因此,当查找结果多于一条,将显示结果列表;反之显示查找结果的详细信息。
获取命令的参数信息:
help cmdname -Parameter <ParameterName>
获取本地文档
PowerShell 中默认不包含帮助文件,但可以联机查看帮助主题,或使用 Update-Help cmdlet
将帮助文件下载到本地或在网站发布更新的时候更新本地文档。
Update-Help (Microsoft.PowerShell.Core) - PowerShell | Microsoft Docs。
Update-Help \
[-UICulture en-US,zh-CN] # 指定文档语言
[-Module Microsoft.PowerShell*] # 更新指定模块的文档(默认更新所有已安装的模块)
-SourcePath path # Save-Help
开发环境
Debugging with Visual Studio Code
变量
PowerShell accepts and returns .NET objects, rather than text.
设置变量:
$JAVA_HOME="C:\tools\java"
Set-Variable -Name 'JAVA_HOME' -Value 'C:\tools\java' # -> set*
*
:set
是Set-Variable
的别名,与cmd
的变量设置命令set
无关。
==变量名不区分大小写==。
输出变量:
$JAVA_HOME # => echo $JAVA_HOME
$JAVA_HOME.ToUpper() # 调用变量对象的属性或方法
$v=Get-Variable -Name 'JAVA_HOME' # get (Name,Value) object
$v.Value
数据类型
空值
Everything you wanted to know about $null - PowerShell | Microsoft Docs
字符串
字符串需要使用''
或""
进行表示,否则相应内容将被视为shell命令。==字符串使用+
拼接==。
Everything you wanted to know about variable substitution in strings - PowerShell | Microsoft Docs
裁剪字符串
str.Trim() # TrimEnd/TrimStart
str.Trim("a", " ") # 可指定多个裁剪模式(单个字符)
返回新的对象。
分割字符串
$array="abcdefghi".split("de") # -> -split运算符
数组
许多命令(如Get-Process
)的返回值都是一个数组。手动构造数组方法:
$data=@('Zero','One','Two','Three') # 空数组 $data = @()
$data=('Zero','One','Two','Three') # => $data = 'Zero','One','Two','Three'
数组元素可换行声明,此时两行间的元素不需要通过
,
分隔。
通过迭代构造数组:
$array = 1..5 | ForEach-Object { "ATX-SQL-$PSItem" }
$array = foreach ( $node in (1..5)){ "ATX-SQL-$node" }
数组默认类型为[PSObject[]]
,即其元素都继承自PSObject
。在创建数组时可指定严格的类型限制:
[int[]] $numbers = 1,2,3
预分配内存的数组:
$data = [Object[]]::new(4)
嵌套数组:
$data = @(
@(1,2,3), # 嵌套数组元素换行时仍需","分隔
@(4,5,6),
@(7,8,9)
)
$data[1][2] # -> 6
多维数组:
[string[,]]$rank2 = [string[,]]::New(3,2)
数组属性
Write-Output -NoEnumerate $data | Get-Member # 获取数组的属性和方法
$data | Get-Member # 获取数组元素的属性和方法
$data.Count # 数组元素数量 => $data.Length
$data.Rank # 数组维数
不仅数组可以获取长度,标量对象也可(返回1),空数组长度为0(特别地
$null.count->0
,注意区别)。
访问元素
$data[i] # 0-based index
$data[0,2,3] # 获取子数组(可添加重复编号以生成重复元素)
$data[1..3] # 切片(区间可反向,即"3..1:")
$data[-1] # 负索引
$data[i,-j] # => [i,i-1,...0,-1,...-j] (与Python负索引语义不同)
访问不在数组长度范围内元素将返回
$null
而非产生异常。
i..j
将自动生成一个整数数组。
访问数组元素属性(链式调用):
$data[0].PropName
$data.PropName # 返回所有元素的PropName返回值组成的新数组
更新数组
$data[2] = 'dos' # 索引编号超过数组长度将产生异常
$data.Clear() # 重置数组元素的值为默认值
迭代数组
$data.foreach({"Item [$PSItem]"}) # => $data.foreach{"Item [$PSItem]"}
$data | ForEach-Object {"Item: [$PSItem]"} # $PSItem => $_
foreach ( $node in $data ){ "Item: [$node]" }
for ( $index = 0; $index -lt $data.count; $index++){
"Item: [{0}]" -f $data[$index]
}
switch( $data ) {...} # 对数组每个元素执行分支判断
当数组元素类型为值类型时,使用for
语句块可在迭代数组时对其进行更新。反之,如果为引用类型,则其他迭代语句也可对数组元素的属性进行更改。
ForEach-Object -Parallel
[7.x]:管道并行。
数组对象运算
数组对象运算都将产生新的数组对象。
-
字符串拼接:使用连接符将数组内容拼接为一个字符串对象。
$data -join '-'
-
替换:
$data -replace 'ATX','LAX' # 对数组每个元素执行替换
-
查找:返回
True|False
。-contains, -notcontains
,-in, -notin
$data -contains 'green' # => 'green' -in $data
-
比较或匹配过滤(
-eq
,-ne
,-match
):数组与对象比较返回匹配对象(或子数组):$data -eq 'green' $servers -match 'SQL' # => $servers | Select-String SQL
判断数组对象是否为
$null
,应该使用$null -eq $array
避免上述语法对数组的$null
值的筛选。 -
追加:
$data = $data + 'four' # $data += 'four'
-
拼接:
$array=$array1+$array2 $array = $array * 3 # 复制并拼接(使用这种方法可构造初始值为固定值的数组)
数组过滤
基于数组元素或元素属性的值过滤元素。如果数组元素本身就是字符串对象,则直接在迭代语句中使用$_
。
$data | Where-Object {$_.Name -eq w32time}
$data.Where({$_.FirstName -eq 'Kevin'}) # 使用成员函数
$data | Select-Object -First 3
分组统计
$data | Group-Object -Property ModuleName |
Sort-Object -Property Count -Descending
字典(hashtable)
$hashtable = @{}
$hashtable['key'] = $value
字典可传递给命令,以代替逐个传递命令行参数,方便动态构造传入参数。
Everything you wanted to know about hashtables - PowerShell | Microsoft Docs
运算符
具有相同优先级的运算符从左到右依次计算。例外:赋值运算符、类型转换运算符、和取反运算符(!
,-not
,-bnot
)从有至左计算。
可以使用()
来显式限定优先计算的部分表达式。
运算符优先级从高到低2:
-
$(), @(), (), @{}
-
. ?.
(member access) -
::
(static) -
[0] ?[0]
(index operator) -
[int]
(cast operators)[datetime]$birthday = "1/10/66" # 将birthday转换为datetime类型
-
-split
(unary) -
-join
(unary) -
,
(comma operator) -
++ --
:自增运算符,支持前置或后置。 -
! -not
:逻辑取反运算。 -
..
(range operator) -
-f
(format operator)"{0:N2} - {1}" -f 10 1.5
-
-
(unary/negative) -
* / %
-
+ -
-
以下命令具有同等优先级:
-
-split -join
(binary):分割字符串(合并见数组运算)。$array="abcdefghi" -split "de" # -> $array="abcdefghi".split("de")
-
-is -isnot
:判断是否为.Net Framework类型。42 –is [int]
-
-as
:类型转换。$a = 42 –as [String]
-
-eq -ne -gt -ge -lt -le
:比较运算符。涉及字符串比较的运算符默认为大小写不敏感的,带前缀c
的运算符(-ceq
)为大小写敏感的(具有同等优先级)。不支持
==,!=,>,<=,<,<=
。 -
-match -notmatch
:正则表达式匹配,返回是否匹配; -
-like -notlike
:通配符匹配; -
-in -notIn
,-contains -notContains
-
-replace
:字符串替换。"abcde" -replace "bc", "TEST" # replace bc with TEST # aTESTde
-
-
-band -bnot -bor -bxor -shr -shl
:位运算,-shl, -shr
(移位)。 -
-and -or -xor
:逻辑运算。 -
以下命令非真正的运算符而是PowerShell命令语法的一部分,在命令解释执行过程中具有最低优先级。
-
.
(dot-source) -
&
(call) -
? <if-true> : <if-false>
(Ternary operator) -
??
(null-coalese operator) -
|
(pipeline operator) -
> >> 2> 2>> 2>&1
-
&& ||
(pipeline chain operators) -
= += -= *= /= %= ??=
:赋值运算符。$result=$a*$b
-
容器类型
数组定义后无法增加元素,PowerShell可调用多种.NET容器类型以解决此问题。
ArrayList
$myarray = [System.Collections.ArrayList]::new()
[void]$myArray.Add('Value') # [void] to suppress return value.
List
ArrayList
不支持泛型,因此类似于数组默认存储PSObject
元素。List
类型支持泛型(类似于数组声明时限定类型):
$mylist = [System.Collections.Generic.List[int]]::new()
$mylist = [System.Collections.Generic.List[int]]@(1,2,3) # 将数组转换为List
对于类型元素多样的情况,也可使用
PSObject
作为类型参数。
List
和ArrayList
都支持元素的的增加和删除。
[void]$myList.Remove("Two") # -> True|False: if element is found
[void]$drives.Remove($drives[2]) # remove reference type
StringBuilder
https://powershellexplained.com/2017-11-20-Powershell-StringBuilder/
其他容器类型
时间日期
date=Get-Date \
-Format "dddd MM/dd/yyyy HH:mm K" \ # 返回个格式化字符串。
-UFormat "%A %m/%d/%Y %R %Z" \
-DisplayHint Date \ # 仅显示日期
-Year 2020 -Month 12 -Day 31 \ # 用户初始化
| Specifier | Definition |
| --- | --- |
| `dddd` | Day of the week - full name |
| `MM` | Month number |
| `dd` | Day of the month - 2 digits |
| `yyyy` | Year in 4-digit format |
| `HH:mm` | Time in 24-hour format -no seconds |
| `K` | Time zone offset from Universal Time Coordinate (UTC) |
| Specifier | Definition |
| --- | --- |
| `%A` | Day of the week - full name |
| `%m` | Month number |
| `%d` | Day of the month - 2 digits |
| `%Y` | Year in 4-digit format |
| `%R` | Time in 24-hour format -no seconds |
| `%Z` | Time zone offset from Universal Time Coordinate (UTC) |
.NET format specifiers (/dotnet/standard/ba se-types/custom-date-and-time-format-strings?view=netframework-4.8)
date.DayOfYear
$timelabel = Get-Date -Format 'yyyy-MM-ddTHHmmss'
New-Item -Path C:\Test\$timelabel -Type Directory
内置变量
$PSVersionTable # Powershell版本信息
$PROFILE # Powershell配置文件路径
对象
使用Get-Noun
方法获取对象,其中None
代表对象类型。
对象成员
获取对象类型,及其成员属性/方法信息。
$Obj | Get-Member
$Obj | Get-Member -MemberType {Method|Property...} -Name name
Get-Member
仅显示默认显示的成员。如果要显示所有成员,可使用Select-Object
筛选对象属性值,返回仅包含指定属性(模式)的对象。
$Obj | Select-Object -Property {*|FriendlyName,Issuer}
-ExpandProperty SerialNumber # 将返回值转换为字符串而非对象
*
获取对象所有属性,反之给出要获取的属性名列表(可包含通配符)。如果管道输入一个序列,则返回每个对象的属性值。
对象方法
对象方法通常用于修改对象。
访问对象属性
$x=$myObject.PropertyName
动态访问对象的属性:
$PROP = 'Name'
$myObject.$PROP # $myObject."Name" => $myObject.Name
Providers
提供访问数据的统一接口,数据以类似文件系统的树形结构组织。
Get-PSProvider
列出所有支持的数据接口类型,包括文件系统、证书目录、注册表等。特别地,==PowerShell的函数、环境变量==等也支持该接口。
Get-PSProvider
# Name Capabilities Drives
# ---- ------------ ------
# Registry ShouldProcess, Transactions {HKLM, HKCU}
# Alias ShouldProcess {Alias}
# Environment ShouldProcess {Env}
# FileSystem Filter, ShouldProcess, Credentials {C, D, E, F}
# Function ShouldProcess {Function}
# Variable ShouldProcess {Variable}
# Certificate ShouldProcess {Cert}
# WSMan Credentials {WSMan}
Get-PSDrive
获取所有支持类型的数据源实例信息。
Get-PSDrive
# Name Used (GB) Free (GB) Provider Root
# ---- --------- --------- -------- ----
# Alias Alias
# Cert Certificate \
# C 256.94 674.00 FileSystem C:\
# D 310.46 1552.56 FileSystem D:\
# E 920.11 6531.80 FileSystem E:\
# F FileSystem F:\
# Env Environment
# Function Function
# HKCU Registry HKEY_CURRENT_USER
# HKLM Registry HKEY_LOCAL_MACHINE
# Variable Variable
# WSMan WSMan
省略了
CurrentLocation
属性,调整了显示顺序。
使用Get-ChildItem
读取数据源路径下的数据。
Get-ChildItem -Path Cert:\LocalMachine\CA
Get-ChildItem -Path Function:
路径的根为
Name:
,其中Name
为数据源实例名称,如C:
、Cert:
等。
Services
Get-Service <Name>
调用服务的方法:
$service=$(Get-Service -Name w32time)
$service.Stop()
成员方法可用于修改获取的对象,而通常没有相关
cmdlet
直接修改对象。
自定义对象类型
$obj = [pscustomobject]@{
FirstName='Kevin';
LastName='Marquette'
}
添加和删除属性
$myObject | Add-Member -MemberType NoteProperty -Name 'ID' -Value 'KevinMarquette'
$myObject.psobject.properties.remove('ID')
添加方法
$scriptBlock = {...} # 使用this引用目标对象
Add-Member -MemberType ScriptMethod -InputObject $myObject -Name 'ToHashtable' -Value $scriptBlock
语法
语句
使用;
在一行书写多条语句;
换行
,
,{}
,[]
,()
,;
,=
,'
,"
可以支持命令跨行书写。
ps_cmd (expr) # "(...)" 优先计算子表达式并返回值
如果命令中包含需要首先展开的参数,则使用&
对参数进行展开,然后执行展开后的命令语句。
& $str_cmd $str_opts # 执行字符串参数所表示的命令
==在行末使用`
强制命令换行以增强可读性==,换行命令间可包含多行注释内容<#...#>
。
引号
In PowerShell, you should always use single quotes instead of double quotes unless the contents of the quoted string contains a variable that needs to be expanded to its actual value. By using single quotes, PowerShell doesn't have to parse the contents contained within the quotes so your code runs a little faster.
注释
单行注释:#
后续内容为注释;
多行注释:<# comment #>
。
管道
通过管道传递对象(变量、数组)将多个命令连接起来。
dir | Sort-Object -Descending | Select-Object -First 1
使用管道操作符连接的命令可在操作符后换行,以方便阅读。
命令必须产生输出才能传递给管道,使用-PassThru
参数强制命令输出内容。通过帮助文档可查看命令的输入和输出要求(INPUT
,OUTPUT
),查看参数帮助文档以确定参数值是否接受管道输入以及接受输入的类型(Accept pipeline input? True (ByValue, ByPropertyName)
)。
Get-Command -ParameterType ServiceController
帮助文档中可能会给出命令的输入输出说明(是否接受管道输入)。
非PowerShell命令输出的文本行会被自动转换为字符串对象,因此后续命令可基于字符串对象进行计算(如过滤)。
左侧过滤优先
优先使用命令参数过滤返回结果(除非过滤条件没有对应参数支持);对返回结果进行过滤(Where-Object
)可能产生较大开销。
右侧格式化优先
尽可能最后对数据执行格式化输出(如Format-Table
)。
流程控制
分支
if (<result1-to-be-matched> -eq (<test-expression>)) {<action>}
Everything you wanted to know about the if statement - PowerShell | Microsoft Docs
switch [-regex| -wildcard| -exact] [-casesensitive](<test-expression>)
{
<result1-to-be-matched> {<action>}
<result2-to-be-matched> {<action>}
default { <action-scriptblock> }
}
默认为精确比较(
-exact
)。如果输入对象为数组,则对每个元素进行计算。
Everything you ever wanted to know about the switch statement - PowerShell | Microsoft Docs
循环
for ($i = 1; $i -lt 5; $i++) {
Write-Output "Sleeping for $i seconds"
Start-Sleep -Seconds $i
}
do{ statements } until (cond_expr)
do{ statements } while (cond_expr)
while (cond_expr) { statements }
跳转
使用break
,continue
,return
控制循环执行(loop, switch)。
labeled continue
用于连续中断多层循环。
:labelA for ($i = 1; $i -le 10; $i++) {
:labelB for ($j = 1; $j -le 10; $j++) {
:labelC for ($k = 1; $k -le 10; $k++) {
if ($conditionA) {
continue labelA # 连续中断
else if ($conditionB) {
continue labelB # 等效于brek
} else {
$condition = Update-Condition
}
}
}
}
异常处理
try { CmdName -ErrorAction Stop } catch {...}
Only terminating errors are caught.
Everything you wanted to know about exceptions - PowerShell | Microsoft Docs
函数
函数命名遵循Verb-Noun
原则(通过Get-Verb
查看常用动词)。
function Get-Version {
[CmdletBinding()] # << turns into an advanced function
param (
[Parameter(Mandatory)] # 必须提供的参数
[String[]]$ComputerName, # 声明类型以在运行时自动执行参数类型校验
[ValidateNotNullOrEmpty()] # 可选参数
[string[]]$ComputerName = $some_value, # 可选参数的默认值
[Parameter(Mandatory,ValueFromPipeline)] # 接受管道传递参数(by value
[String[]]$ComputerName, # ValueFromPipelineByPropertyName(by name)
)
dynamicparam {<statement list>}
begin { begin_statements }
process { process_statements }
end { end_statements }
}
function Get-Version([type1]$param1[,[type2]$param2]) {}
通过param
声明输入参数,参数命名尽量与内置标准命令方式一致,多个参数以,
分隔;对于较为简单的参数声明,也可以直接在函数名后声明。
输入参数
参数类型
- 命名参数:通过
param()
语句声明的参数,可以指定默认值,为指定默认值的参数在运行时必须提供参数值,否则函数报错。 - 位置参数:非命名参数,通过
$args[i]
数组访问。可通过@args
将所有参数传递给其他函数或命令。 - 开关参数:通过
param()
声明类型为[switch]
的参数。不需要为该参数提供值,当该参数选项出现在命令时,参数的的值为True
。 - 动态参数:
从管道读取参数
begin
、process
和end
语句块用于处理管道输入。begin
和end
会在函数开始和结束时分别被执行一次,而process
语句块则对每一个管道输入对象$_
执行一次。
如果声明了以上语句块,则函数的所有语句都必须位于语句块中。未声明语句块的情况,所有语句相当于位于end
语句块中。
过滤器
过滤器(Filters)可被看作只有process
代码块的函数。
返回值
函数的返回值可以在终端显示、赋值给变量或转递给其他函数/命令。函数中可通过调用的命令返回数据,或通过调用return
返回数据对象。return
语句会立即令函数返回。
高级函数
高级函数具有自动添加的公共参数,例如Debug
和Verbose
。
Everything you wanted to know about ShouldProcess - PowerShell | Microsoft Docs
cmdlets
注释文档
函数注释文档可位于:函数体开头(位于{
之后的行);函数体结束前(位于}
之前),或==函数定义关键字前function
的行(不可有空行隔开)==。
脚本注释文档位于脚本开始或结束。
脚本模块注释文档.psm1
与函数注释文档语法一致。
<#
.SYNOPSIS
函数用途简要说明。
.DESCRIPTION
函数功能的详细描述。
.PARAMETER ComputerName
参数说明
.EXAMPLE
使用示例。
.INPUTS
输入类型
.OUTPUTS
输出类型
.NOTES
Author: Mike F Robbins
Website: http://mikefrobbins.com
Twitter: @mikefrobbins
#>
PARAMETER
和EXAMPLE
可声明多次。
命名空间
在脚本开始位置引入命名空间,方便引用其中的类型和方法。
using namespace System.Collections.Generic
$myList = [List[int]]@(1,2,3)
作用域
about Scopes - PowerShell | Microsoft Learn
输入输出
Get-Content [-Path] filepath # -> cat, type
Write-Output 'message' > filename # -> echo
'message' > filename
'message' | Out-File -FilePath filename
不同级别的输出函数:
Write-Verbose -Message "message" # 仅在开启Verbose选项时输出
Write-Debug
Write-Information
Write-Warning
Write-Error
重定向
输出重定向
n>, n>>
:输出流n=
:*
All output;1
Success output;2
Errors;3
Warning messages;4
Verbose output;5
Debug messages。
吸收输出
expr | Out-Null
,expr > $null
;[void] expr
;$null=expr
;
格式输出
当输出为多个对象组成的列表格式(即key:value
形式),可通过Format-Table
将其转换为表格形式:
$obj | Select-Object -Property Name,Type,Status | Format-Table
反之,可以将表格输出转换为列表输出。
Format-List
Format-*
命令会将输出对象封装为Foramt
对象,因此可能不再能传递给其他命令。
文本模式输出
将对象转换为文本输出(可用于传统基于文本的命令进行后续处理):
Find-Module *cim* | Out-String -Stream | grep CimSession
-Stream
将输出按行分解便于后续处理。
-Width
设置输出宽度,避免换行或截断。
网络应用
The
Invoke-WebRequest
cmdlet sends HTTP and HTTPS requests to a web page or web service. It parses the response and returns collections of links, images, and other significant HTML elements.
Invoke-WebRequest # alias => curl,wget
-Uri <uri>
-Headers <dict> # http header
-Body <obj> # http body
-InFile <file> # read request from file
-OutFile <filename> # 未指定则输出到管道
-Method <m> # http method: get/put/post...
脚本
脚本文件类型.ps1
。
在当前Shell环境执行脚本。
. 'c:\scripts\sample.ps1'
脚本文件编码
PowerShell 5.x默认使用的是本地化编码方案(如GBK/936),因此如果包含非ASCII码文字的脚本应该使用对应区域的本地化编码方案保存。(例外:VS Code中的集成终端代码页为936,但能正确读取UTF-8编码)
PowerShell 7.x默认使用UTF-8/65001编码。
PowerShell解释器会首先读入整个脚本文件内容,并检查语法错误。如果出现编码问题导致语法错误,则会直接抛出语法错误而不执行文件。
通过启动配置$Profile
修改终端的默认编码(由于.NET缓存机制的原因,在启动后的PowerShell终端中调用chcp
命令无效,chcp
在cmd
中是有效的):
$OutputEncoding = [console]::InputEncoding `
= [console]::OutputEncoding `
= New-Object System.Text.UTF8Encoding
作用域
全局作用域
位于脚本中的函数的作用域为脚本(Script scope),当脚本被加载或执行完后,脚本作用域中的函数不再可见。使用.
命令加载脚本中的函数到全局作用域(Global scope)。
. .\My-Script.ps1
脚本模块
以.psm1
保存的脚本。如果脚本模块保存在PoweShell模块搜索路径下,则会被自动加载;反之,需要手动导入。
Export-ModuleMember -Function Get-PublicFunction # 在模块中导出定义公开函数
为模块创建元数据(元数据存储路径通常和模块位于同一路径下):
New-ModuleManifest -Path $ModulePath\MyScriptModule\MyScriptModule.psd1
-RootModule MyScriptModule # 必须指定
-Author 'Mike F Robbins'
-Description 'MyScriptModule'
-CompanyName 'mikefrobbins.com'
Update-ModuleManifest # 更新元数据,重复调用New-ModuleManifest会导致GUID变化
导出的公开函数也可在元数据文件中指定:
FunctionsToExport = 'Get-PublicFunction'
运行环境
环境变量
读取环境变量
Get-ChildItem env: # 注意结尾的“:”
Get-ChildItem Env:JAVA_HOME # => Get-ChildItem Env:\JAVA_HOME
echo $Env:JAVA_HOME # echo ${Env:JAVA_HOME} => echo ${Env:\JAVA_HOME}
Get-ChildItem Env: | Format-Table -Wrap -AutoSize
设置环境变量
$Env:JAVA_HOME='C:\tools\jdk' # 仅当前会话有效
$Env:Path='C:\tools\jdk;'+$Env:Path
路径搜索优先级:从左至右搜索,将新路径置于左侧将覆盖已有配置。
脚本输入参数
脚本的输入参数格式与函数输入参数语法格式一致。
param (
[string]$Target = '.\src',
[string]$Source = '.\target'
)
定义的参数可在命令行中获得自动补全功能。
语句的退出状态码
$? # return 'True'/'False' for success/error
$LastExistCode # Return 0 for success
执行策略
PowerShell 执行策略是一项安全功能,用于控制 PowerShell 加载配置文件和运行脚本的条件。 此功能有助于防止恶意脚本的执行。可以为本地计算机、当前用户或特定会话设置执行策略。 你还可以使用组策略设置为计算机和用户设置执行策略。本地计算机和当前用户的执行策略存储在注册表中。 不需要在 PowerShell 配置文件中设置执行策略。 特定会话的执行策略仅存储在内存中,并在会话关闭时丢失。
执行策略不是限制用户操作的安全系统。 例如,当用户无法运行脚本时,可以通过在命令行中键入脚本内容来轻松地绕过策略。 相反,执行策略可帮助用户设置基本规则并防止无意中违反它们。
策略 | 详情 |
---|---|
AllSigned | 脚本必须由信任发布方签名;在未确认的脚本运行前提示用户;==可能面临运行已签名的恶意脚本的风险==。 |
Bypass | 不会阻止且不会产生警告或信息; |
Default | 默认策略:Restricted for Windows clients.RemoteSigned for Windows servers. |
RemoteSigned | 来自互联网的脚本需要来自信任发布方的数字签名;本地脚本允许执行。 |
Restricted | ==允许单独执行命令,但不允许运行脚本==; |
Undefined | If the policy in all scopes is Undefined, use Default. |
Unrestricted | 非Windows主机的默认策略;未签名脚本可以运行,非本地脚本运行前警告用户。 |
设置策略
Set-ExecutionPolicy <policy>
标准库
WMI和CIM
Windows Management Instrumentation (WMI)模块:弃用。
Common Information Model (CIM)模块:跨平台,通过CIM可访问WMI。
Get-Command -Module CimCmdlets
Get-CimInstance -Query 'Select * from Win32_BIOS' # WMI Query Language (WQL)
Get-CimInstance -ClassName Win32_BIOS
远程管理(指定ComputerName
参数):以域管理员启动PowerShell并执行
Get-CimInstance -ComputerName dc01 -ClassName Win32_BIOS
或者首先提供凭据(密码)并创建CIM会话:
$CimSession = New-CimSession -ComputerName dc01 -Credential (Get-Credential)
Get-CimInstance -CimSession $CimSession -ClassName Win32_BIOS
远程登录
从Windows可选功能中安装OpenSSH Server。
Installation of OpenSSH For Windows Server 2019 and Windows 10
远程登录后默认的Shell是cmd.exe
,如果要启用PowerShell
,可在命令窗口中运行powershell
,或者直接在远程登录命令中运行该命令。
ssh user@host "chcp65001 && powershell"
直接进入Powershell会导致中文乱码,需要先切换编码到
UTF-8
。
PowerShell Remoting Over SSH - PowerShell | Microsoft Docs
附录
cmd
注释语句:
REM comment something
使用^
对单条命令进行换行,^
后不可包含任何符号。
变量
变量名不区分大小写。查看变量:
set [ | more]
set var # print: key=value
echo %variable% # 使用`%%`读取变量的值,未定义的变量将打印变量名
定义console环境变量
set variable=value # 必须设用set,不支持VAR=VALUE
PATH
既是环境变量,也是一个命令(单独使用PATH
可显示PATH
变量的值,也可使用PATH=value
为PATH
变量赋值,普通变量必须使用set
命令)。
参数变量:
%1 %2 %3 %4 %5 %6 %7 %8 %9
%~dp0
获取当前执行文件所在目录。
字符串
字符串不需要使用引号表示,单双引号均为普通字符。将两个字符串连接即视为字符串拼接。
环境变量
echo %USERPROFILE% # 用户目录
echo %PROGRAMDATA% # 应用程序配置文件路径
chcp 65001 # 支持PowerShell
Windows Code page 936, is Microsoft's character encoding for simplified Chinese, one of the four DBCSs for East Asian languages. Originally, Windows-936 covered GB 2312 (in its EUC-CN form), but it was expanded to cover most of GBK with the release of Windows 95.
https://en.wikipedia.org/wiki/UTF-8#Official_name_and_variants.
Windows Code Page: 936/1386 (GBK), 950/1370 (Big5), 1200 (UTF-16LE), 1201 (UTF-16BE), 54936 (GB18030), 65001 (UTF-8).
环境变量作用域
setlocal # 执行之后所做的环境改动只限于批处理文件直到endlocal。
endlocal # 脚本结束前隐式执行
语句
dir & echo foo
dir && echo foo # execute only if the first exited successfully
batch file - How do I run two commands in one line in Windows CMD? - Stack Overflow
常用命令
help [cmd] # cmd /?
call jobname.bat
调用脚本。
pause
暂停。
exit
退出。
cd [/D] path
切换当前目录。
type file
输出文件内容。
流程控制
if [not] ERRORLEVEL <number> <command> [else <expression>]
if [not] <string1> == <string2> <command> [else <expression>]
if [not] exist <filename> <command> [else <expression>]
errorlevel
:上一条命令的执行状态。
for {%% | %}<variable> in (<set>) do <command> [<commandlineoptions>]
# for %f in (*.doc *.txt) do type %f
控制台输入输出
echo on|off # 控制是否回显命令行提示符
echo some string
字符串不需要使用引号表示,单双引号均为普通字符。